using System;
using OracleInternal.Json.Sql;

namespace OracleInternal.Json.Binary
{
	internal abstract class OsonAbstractArray : OsonStructure
	{
		internal OsonAbstractArray(OsonContext ctx, int pos)
			: base(ctx)
		{
			Init(pos);
		}

		protected OsonAbstractArray(OsonContext ctx)
			: base(ctx)
		{
		}

		internal string GetJsonString(int i)
		{
			int offsetWithError = GetOffsetWithError(i);
			return GetStringInternal(offsetWithError) ?? throw new InvalidCastException();
		}

		internal bool GetBoolean(int i)
		{
			int offsetWithError = GetOffsetWithError(i);
			bool booleanInternal = GetBooleanInternal(offsetWithError);
			if (!booleanInternal)
			{
				throw new InvalidCastException();
			}
			return booleanInternal;
		}

		internal bool GetBoolean(int i, bool d)
		{
			int childOffset = GetChildOffset(i);
			if (childOffset == -1)
			{
				return d;
			}
			bool booleanInternal = GetBooleanInternal(childOffset);
			if (!booleanInternal)
			{
				return d;
			}
			return booleanInternal;
		}

		internal int GetInt(int i)
		{
			int offsetWithError = GetOffsetWithError(i);
			return ((OracleJsonNumber)GetValueInternal(offsetWithError)).IntValue();
		}

		internal int GetInt(int i, int d)
		{
			int childOffset = GetChildOffset(i);
			if (childOffset == -1)
			{
				return d;
			}
			object valueInternal = GetValueInternal(childOffset);
			if (!(valueInternal is OracleJsonNumber))
			{
				return d;
			}
			return ((OracleJsonNumber)valueInternal).IntValue();
		}

		internal bool IsNull(int i)
		{
			int offsetWithError = GetOffsetWithError(i);
			return IsNullInternal(offsetWithError);
		}

		internal bool Contains(object value)
		{
			for (int i = 0; i < m_size; i++)
			{
				if (GetValueInternal(GetChildOffset(i)).Equals(value))
				{
					return true;
				}
			}
			return false;
		}

		internal object[] ToArray()
		{
			object[] result = new object[m_size];
			CopyToArray(result);
			return result;
		}

		internal object GetInternal(int i)
		{
			return GetValueInternal(GetOffsetWithError(i));
		}

		internal int IndexOf(object o)
		{
			for (int i = 0; i < m_size; i++)
			{
				if (GetInternal(i).Equals(o))
				{
					return i;
				}
			}
			return -1;
		}

		internal int LastIndexOf(object o)
		{
			int result = -1;
			for (int i = 0; i < m_size; i++)
			{
				if (GetInternal(i).Equals(o))
				{
					result = i;
				}
			}
			return result;
		}

		public override OracleJsonType GetOracleJsonType()
		{
			return OracleJsonType.ARRAY;
		}

		protected override void Init(int pos)
		{
			base.Init(pos);
			int uB = m_ctx.m_osonBuffer.GetUB1(pos);
			InitChildOffseUb(uB);
			int num = uB & 0x18;
			m_childArrayOffset = pos + 1;
			switch (num)
			{
			case 0:
				m_childArrayOffset++;
				m_size = m_ctx.m_osonBuffer.GetUB1(pos + 1);
				break;
			case 8:
				m_childArrayOffset += 2;
				m_size = m_ctx.m_osonBuffer.GetUB2(pos + 1);
				break;
			case 16:
				m_childArrayOffset += 4;
				m_size = m_ctx.m_osonBuffer.GetUB4int(pos + 1);
				break;
			}
		}

		protected override int GetChildOffset(int i)
		{
			if (i < 0 || i >= m_size)
			{
				return -1;
			}
			OsonHeader header = m_ctx.GetHeader();
			if (m_childOffsetUb == 2)
			{
				return m_ctx.m_osonBuffer.GetUB2(m_childArrayOffset + i * 2) + header.GetTreeSegmentOffset();
			}
			return m_ctx.m_osonBuffer.GetUB4int(m_childArrayOffset + i * 4) + header.GetTreeSegmentOffset();
		}

		private void CopyToArray(object[] result)
		{
			for (int i = 0; i < m_size; i++)
			{
				result[i] = GetValueInternal(GetChildOffset(i));
			}
		}

		protected int GetOffsetWithError(int i)
		{
			int childOffset = GetChildOffset(i);
			if (childOffset == -1)
			{
				throw new IndexOutOfRangeException();
			}
			return childOffset;
		}
	}
}
